package dbPhase.hypeerweb;


/**
 * The DownPointingNodeState is used when a node has downpointers and does the correct find and search
 * for when a node is a downpointing node.
 *
 * @pre DownPointingNodeState singleton
 *
 * @post none
 *
 * @author scott44
 *
 */
public class DownPointingNodeState extends NodeState {

	static DownPointingNodeState singleton;

	/**
	 * Constructor for a DownPointingNodeState
	 *
	 * @pre none
	 *
	 * @post none
	 */
	private DownPointingNodeState() {

	}

	/**
	 * getSingleton makes it so there is only one instance of the DownPointingNodeState for any node
	 * who needs it to use.
	 *
	 * @pre singleton == null or not if it is null you create the one instance
	 *
	 * @return singleton - the one instance of singleton
	 */
	static DownPointingNodeState getSingleton() {
		if (singleton == null) {
			singleton = new DownPointingNodeState();
		}
		return singleton;
	}


	public static final int STATE_ID = 2;

	@Override
	/**
	 * find - in the down pointing node state this finds the biggest neighbor and calls another find
	 * if that is null it gets the smallest down pointer and calls search on that.
	 *
	 * @pre none
	 *
	 * @param Node newNode - is the new node that will eventually be added to the HyPeerWeb
	 *
	 * @param Node thisNode- the node that has the information to get to the next node
	 */
	public Node find(Node thisNode ) {

		Node biggestNeighbor = thisNode.getBiggestNeighbor();
		if (biggestNeighbor != Node.NULL_NODE) {
			return biggestNeighbor.nodeState.find(biggestNeighbor);
		}
		else {
			return thisNode;
		}
	}

	@Override
	/**
	 * search - in the down pointing node state it checks if the lower bound which is passed in is one off
	 * the this nodes webid and if so then you add the node to ththis finds the biggest neighbor and calls another find
	 * if that is null it gets the smallest down pointer and calls search on that.e HyPeerWeb at that location. Otherwise
	 * it gets the smallest down pointer again and calls search again.
	 *
	 * @pre none
	 *
	 * @param lb - the lowerbound to check against when the function is called.
	 *
	 * @param ub - the upperbound to hopefully become smaller and smaller.
	 *
	 * @param Node newNode - is the new node that will eventually be added to the HyPeerWeb
	 *
	 * @param Node thisNode- the node that has the information to get to the next node
	 */
	public Node search(int lb, int ub, Node thisNode ) {
		if (thisNode.webId.getValue() == lb + 1) {
			return thisNode;
		}
		else if (lb == thisNode.getSmallestNeighbor().getWebIdValue()
				&& ub == thisNode.getSmallestDownPointer().getWebIdValue()) {
			Node biggestNeighbor = thisNode.getBiggestNeighbor();
			return biggestNeighbor.nodeState.search(lb, ub, biggestNeighbor);
		}
		else {
			Node smallestDownPointer = thisNode.getSmallestDownPointer();
			return smallestDownPointer.nodeState.search(thisNode.getWebIdValue(),
					smallestDownPointer.getWebIdValue(), smallestDownPointer);
		}
	}
	@Override
	/**
	 * getStateId - simply returns the integer value of the DownPointingNodeState
	 *
	 * @pre none
	 *
	 * @return STATE_ID
	 */
	public int getStateId() {

		return STATE_ID;
	}

	/**
	 * toString - returns the string description of the DownPointingNodeState
	 *
	 * @pre none
	 *
	 * @return string - "Down Pointing Node State"
	 */
	@Override
	public String toString() {
		return "Down Pointing Node State";
	}

	@Override
	public Node findDP( Node thisNode) {
		Node biggestNeighbor = thisNode.getBiggestNeighbor();
		if (biggestNeighbor != Node.NULL_NODE) {
			return biggestNeighbor.nodeState.findDP( biggestNeighbor);
		}
		else {
			Node smallestDownPointer = thisNode.getSmallestDownPointer();
			Node parent = thisNode.getSmallestNeighbor();

			return smallestDownPointer.nodeState.searchDP(parent.getWebId().getValue(),
					smallestDownPointer.getWebId().getValue(),  smallestDownPointer);
		}
	}

	@Override
	public Node searchDP(int lb, int ub, Node thisNode) {
		if (thisNode.webId.getValue() == lb + 1) {
			System.err.println("Why is a DP node = lb + 1? ");
		}
		else {
			Node biggestNeighbor = thisNode.getBiggestNeighbor();

			if (biggestNeighbor != Node.NULL_NODE) {
				return biggestNeighbor.nodeState.searchDP(lb, ub, biggestNeighbor);
			}
			else {
			Node smallestDownPointer = thisNode.getSmallestDownPointer();

			return smallestDownPointer.nodeState.searchDP(thisNode.getWebId().getValue(),
					smallestDownPointer.getWebId().getValue(), smallestDownPointer);
			}
		}
		return Node.NULL_NODE;
	}
}
